﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using WebApi.Filters;
using WebApi.Models;
using WebApi.MyServices;

namespace WebApi.Hubs;

/// <summary>
/// SignalR Hub
/// </summary>
public class ChatHub : Hub
{
    /// <summary>
    /// Send message to all clients
    /// </summary>
    /// <param name="message"></param>
    /// <param name="userName"></param>
    /// <param name="context"></param>
    /// <param name="cache"></param>
    /// <param name="catch"></param>
    /// <returns></returns>
    public async Task newMessage(long userName, string message, [FromServices] TodoContext context,
        [FromKeyedServices("SmallCatch")] ICatch @catch,
        [FromKeyedServices(nameof(BigCatch))] ICatch cache)
    {
        Console.WriteLine(@catch.GetCatch("small"));
        Console.WriteLine(cache.GetCatch("Big"));
        var list = context.TodoItems.ToList();
        await Clients.All.SendAsync("messageReceived", userName, message);
    }

    /// <summary>
    /// Send message to caller
    /// </summary>
    /// <param name="connectionId"></param>
    /// <returns></returns>
    public async Task<string> WaitForMessage(string connectionId)
    {
        var message = await Clients.Client(connectionId).InvokeAsync<string>("GetMessage", CancellationToken.None);
        return message;
    }
    /*  
     /// <summary>
     /// Wait for message from client
     /// </summary>
     /// <param name="connectionId"></param>
     /// <param name="cancellationToken"></param>
     /// <returns></returns>
     public async Task<string> WaitForMessage(string connectionId, CancellationToken cancellationToken)
     {
         var message = await Clients.Client(connectionId).InvokeAsync<string>("GetMessage", cancellationToken);
         return message;
     }

     /// <summary>
     /// Send message to group
     /// </summary>
     /// <param name="hubContext"></param>
     /// <param name="connectionId"></param>
     /// <returns></returns>
     public async Task<string> SomeMethod(IHubContext<ChatHub> hubContext, string connectionId)
     {
         var message = await hubContext.Clients.Client(connectionId).InvokeAsync<string>("GetMessage", CancellationToken.None);
         return message;
     }
 */


    /// <summary>
    /// 当连接成功后，获取连接ID，加入到组中
    /// </summary>
    /// <returns></returns>
    public override async Task OnConnectedAsync()
    {
        // 连接成功后，获取连接ID
        await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR User");
        await base.OnConnectedAsync();
    }

    /// <summary>
    /// 当连接断开后，移除连接ID
    /// </summary>
    /// <param name="exception"></param>
    /// <returns></returns>
    public override Task OnDisconnectedAsync(Exception? exception)
    {
        // 连接断开后，移除连接ID 可以不用在这里调用，Groups.RemoveFromGroupAsync 方法会自动调用 OnDisconnectedAsync
        Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR User");
        return base.OnDisconnectedAsync(exception);
    }

    /// <summary>
    /// Throw exception to client
    /// </summary>
    /// <returns></returns>
    /// <exception cref="HubException"></exception>
    public Task ThrowException()
    {
        // 使用 HubException 抛出异常，客户端会收到异常信息
        throw new HubException("this error will be send to client");

        // 使用 Exception 抛出异常，客户端不会收到异常信息
        // throw new Exception("this error will not be send to client");
    }

    /// <summary>
    /// 给特定用户发送消息
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="message"></param>
    /// <returns></returns>
    public Task SendMessageToUser(string userId, string message)
    {
        // 发送消息到指定用户
        return Clients.User(userId).SendAsync("ReceiveMessage", message);
    }

    /// <summary>
    /// 添加用户到组
    /// </summary>
    /// <param name="groupName"></param>
    /// <returns></returns>
    public async Task AddToGroup(string groupName)
    {
        // 将当前连接加入到指定组
        await Groups.AddToGroupAsync(Context.ConnectionId, groupName);

        await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} has joined the group {groupName}");
    }

    /// <summary>
    /// 从组中移除用户
    /// </summary>
    /// <param name="groupName"></param>
    /// <returns></returns>
    public async Task RemoveFromGroup(string groupName)
    {
        // 将当前连接从指定组中移除
        await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
        await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} has left the group {groupName}");
    }

    // 使用自定义对象作为参数，能够向后兼容

    /// <summary>
    /// Get total length of string
    /// </summary>
    /// <param name="parm1"></param>
    /// <returns></returns>
    public int GetTotalLength(TotalLengthReq req)
    {
        var len = req.Parm1.Length;
        if (!string.IsNullOrEmpty(req.Parm2))
        {
            len += req.Parm2.Length;
        }
        return len;
    }

    // 客户端也使用对象参数
    public async Task Broadcast(string message)
    {
        // 发送消息到所有连接
        await Clients.All.SendAsync("ReceiveMessage", new
        {
            Message = message,
            User = Context.User.Identity?.Name,
            ConnectionId = Context.ConnectionId
        });
    }

    /// <summary>
    /// 使用过滤器
    /// </summary>
    /// <param name="message"></param>
    /// <param name="username"></param>
    /// <param name="async"></param>
    /// <param name="void"></param>
    /// <returns></returns>
    [LanguageFilter(FilterArgument = 0)]
    public async Task SendMessage(string async, string username,string async2,string @void)
    {
        Console.WriteLine($"async:{async},void:{@void}");
        await Clients.All.SendAsync("SendMessage",$"{username} says: {async}");
    }

    ///// <summary>
    ///// Net Client Send Message
    ///// </summary>
    ///// <param name="message"></param>
    ///// <param name="user"></param>
    ///// <returns></returns>
    //public async Task NetClientSendMessage(NetClientRequestParam netClient)
    //{
    //    await Clients.All.SendAsync("NetClientReceiveMessage", new {Message=netClient.Message,User = netClient.User});
    //}
}

public class TotalLengthReq
{
    public string? Parm1 { get; set; }

    public string? Parm2 { get; set; }
}

public class NetClientRequestParam
{
    public string? User { get; set; }
    public string? Message { get; set; }
}